/*
 * ServerListenSocket.cpp
 *
 *  Created on: 06-01-2011
 *      Author: Michal Lisicki
 */


#include "ServerListenSocket.h"

#include <iostream>
#include <boost/thread/thread.hpp>
#include <boost/ptr_container/ptr_array.hpp>
#include <boost/lexical_cast.hpp>
#include "ConnectionPool.h"
#include "ClientConnection.h"

using namespace Network;

ServerListenSocket::ServerListenSocket() {
	nextUID_ = (unsigned char) 0;
}
ServerListenSocket::~ServerListenSocket() { }

bool ServerListenSocket::init(int port, int backlog) {
	port_ = port; backlog_ = backlog;
	reset();

#ifdef _WIN32
    WSADATA WsaData;
    WSAStartup(MAKEWORD(2,2), &WsaData);
#endif

	sock_ = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock_ == -1)
		return false;

	target_.sin_family = AF_INET;
	target_.sin_addr.s_addr = htonl(INADDR_ANY);
	target_.sin_port = htons(port_);

	if(bind(sock_, (struct sockaddr *) &target_, sizeof target_) == -1)
		return false;

/*
	// Ustawienie typu nieblokujacego przede wszystkim ze wzgledu
	// na organizacje kodu czytania z gniazda
	#ifdef _WIN32
		DWORD nonBlocking = 1;
		if ( ioctlsocket(sock_, FIONBIO, &nonBlocking ) != 0 ) {
			close();
			return false;
		}
	#else
		int nonBlocking = 1;
		if ( fcntl(sock_, F_SETFL, O_NONBLOCK, nonBlocking ) == -1 ) {
			close();
			return false;
		}
	#endif
*/
	return true;
}

void ServerListenSocket::run() {
	do {
		Packet packet;
		packet = receivePacket();

		if(packet.length_>0 && packet.type_==JOIN) {
			ClientConnection* conPoolClient = ConnectionPool::getInstance().getConnection(packet.from_);
			if(conPoolClient==NULL) {
				if(!ConnectionPool::getInstance().isFull()) {
					std::cout << "cc init" << std::endl;
					ClientConnection* cC = new ClientConnection();
					int pos = ConnectionPool::getInstance().getPosition();

					// Inicjalizuje polaczenie. Przypisuje polaczeniu port
					// w oparciu o pozycje na liscie polaczen
					cC->init(packet.from_, PORT + pos, getNextUID());

					boost::thread thrd(&ClientConnection::run, cC);
					thrd.join();
					ConnectionPool::getInstance().addConnection(cC, pos);
					Packet sPacket(JOIN_ACC,boost::lexical_cast<std::string>(PORT + pos));
					sendPacket(sPacket);
				} else {
					Packet sPacket(JOIN_NAC);
					sendPacket(sPacket);
				}
			} else {
				Packet sPacket(JOIN_ACC,boost::lexical_cast<std::string>(conPoolClient->getPort()));
				sendPacket(sPacket);
			}
		}
		wait(DELTA_TIME);
	} while(true);
}

void ServerListenSocket::reset() {
//	state_ = NOT_CONNECTED;
//	timeoutAccumulator_ = 0.0f;
}

void ServerListenSocket::close() {
#ifdef _WIN32
	closesocket(sock_);
	WSACleanup();
#else
	close(sock_);
#endif
//	state_=NOT_CONNECTED;
}

int ServerListenSocket::getListeningPort() {
	return port_;
}

unsigned char ServerListenSocket::getNextUID() {
	return nextUID_++;
}
/*
void ServerListenSocket::broadcastMsg(Commands::Command* cmd) {
	boost::ptr_array<ClientConnection,MAX_CONN>* connections;
	connections = ConnectionPool::getInstance().getAll();
	std::ostringstream s;
	cmd->serialize( s );
	for(int i=0; i<MAX_CONN; i++) {
		if(!(connections->is_null(i))) {
			std::ostringstream sout = conncetions->at(i).getOutputStream();
			sout << rgjeig ;
			conncetions->at(i).write();
		}
	}
 }
*/
bool ServerListenSocket::isClosed() {
	return false;
}
